package cz.vse.integrace.iag.db;

import com.google.api.client.auth.oauth2.draft10.AccessTokenResponse;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * Bean pro přístup do databáze. Databáze musí podporovat JPA.
 * Slouží pro ukládání tříd Zamestnanec, Oddeleni a Adresa.
 * 
 * @author David Nejedly
 * @version 1.0
 */
@Stateless
public class ZamestnanciDAOBean implements ZamestnanciDAO {

    @PersistenceContext(unitName = "integrace")
    private EntityManager entityManager;
    private static final Logger logger = Logger.getLogger(ZamestnanciDAOBean.class.getName());

    /**
     * Metoda načítá všechny zaměstnance z databáze a vytváří jejich objekty.
     * Pokud není nalezen žádný zaměstnanec je vráceno null.
     * 
     * @return zaměstnanci v databázi
     */
    @Override
    public List<Zamestnanec> getZamestnance() {
        Query query = entityManager.createNamedQuery("ZAMESTANCI_VSE");
        try {
            return (List<Zamestnanec>) query.getResultList();
        } catch (NoResultException e) {
            logger.log(Level.WARNING,
                    "Žádní zaměstnanci nenalezeni", e);
            return null;
        }
    }

    /**
     * Metoda vrací zaměstnace z databáze, podle jeho jména a přímení.
     * 
     * @param jmeno jméno zaměstnance
     * @param prijmeni příjmení zaměstnance
     * @return objekt zaměstnance nebo null, když není nalezen
     */
    @Override
    public Zamestnanec getZamestnanec(String jmeno, String prijmeni) {
        Query query = entityManager.createNamedQuery("ZAMESTNANEC_PODLE_JMENA");
        query.setParameter("jmeno", jmeno);
        query.setParameter("primeni", prijmeni);
        try {
            return (Zamestnanec) query.getSingleResult();
        } catch (NoResultException e) {
            logger.log(Level.SEVERE, "Zaměstnanec nenalezen.", e);
            return null;
        }
    }

    /**
     * Metoda vrací zaměstnace z databáze, podle jeho jména a přímení.
     * 
     * @param zamestneckeCislo číslo zaměstnance
     * @return objekt zaměstnance nebo null, když není nalezen
     */
    @Override
    public Zamestnanec getZamestnanec(int zamestneckeCislo) {
        Query query = entityManager.createNamedQuery("ZAMESTNANEC_PODLE_CISLA");
        query.setParameter("id", zamestneckeCislo);
        try {
            return (Zamestnanec) query.getSingleResult();
        } catch (NoResultException e) {
            logger.log(Level.SEVERE, "Zaměstnanec nenalezen.", e);
            return null;
        }
    }

    /**
     * Metoda načítá všechny oddělení z databáze. Pokud není nalezeno žádné
     * oddělení je vráceno null.
     * 
     * @return seznam oddělení
     */
    @Override
    public List<Oddeleni> getOddeleni() {
        Query query =
                entityManager.createNamedQuery("ODDELENI_VSE");
        try {
            return (List<Oddeleni>) query.getResultList();
        } catch (NoResultException e) {
            logger.log(Level.WARNING,
                    "Žádné oddělení nenalezeno.", e);
            return null;
        }
    }

    /**
     * Metoda načítá oddělení podle čísla oddělení. Pokud oddělení není nalezeno
     * je vráceno null.
     * 
     * @param cisloOdeleni číslo oddělení
     * @return objekt oddělení
     */
    @Override
    public Oddeleni getOddeleni(int cisloOdeleni) {
        Query query = entityManager.createNamedQuery("ODDELENI_PODLE_CISLA");
        query.setParameter("id", cisloOdeleni);
        try {
            return (Oddeleni) query.getSingleResult();
        } catch (NoResultException e) {
            logger.log(Level.SEVERE, "Oddělení nenalezeno.", e);
            return null;
        }
    }

    /**
     * Metoda, která proběhne po zkonstorování objektu implemtující toto 
     * rozhraní.
     */
    @Override
    public void init() {
    }

    /**
     * Metoda ukládá zaměstnance do databáze. 
     * 
     * @param zamestnanec zaměstnanec k uložení
     * @return true, pokud se uložení zdařilo, jinak null
     */
    @Override
    public boolean ulozZamestnance(Zamestnanec zamestnanec) {
        zamestnanec = entityManager.merge(zamestnanec);
        entityManager.flush();
        if (zamestnanec == null) {
            logger.log(Level.WARNING, "Zam\u011bstnanec {0} neulo\u017een", zamestnanec.getCeleJmeno());
            return false;
        } else {
            logger.log(Level.WARNING, "Zam\u011bstnanec {0} ulo\u017een", zamestnanec.getCeleJmeno());
            return true;
        }
    }

    /**
     * Metoda ukládá oddělení do databáze.
     * 
     * @param oddeleni oddělení k uložení
     * @return true, pokud se uložení zdařilo, jinak null
     */
    @Override
    public boolean ulozOddeleni(Oddeleni oddeleni) {
        oddeleni = entityManager.merge(oddeleni);
        entityManager.flush();
        if (oddeleni == null) {
            logger.log(Level.WARNING, "Oddělení {0} neulo\u017eeno", oddeleni.getNazev());
            return false;
        } else {
            logger.log(Level.WARNING, "Oddělení {0} ulo\u017eeno", oddeleni.getNazev());
            return true;
        }
    }

     /**
     * Ukládá zadaný AccessTokenResponse pro OAuht k zaměstnaci, 
     * podle jeho zaměstnaneckého čísla.
     * 
     * @param tokens The AccessTokenResponse to store
     * @param userName The userName associated wit the token
     */
    @Override
    public void ulozToken(AccessTokenResponse tokens, Integer zamId) {
        Zamestnanec zamestnanec = getZamestnanec(zamId);
        zamestnanec.setAccessToken(tokens.accessToken);
        zamestnanec.setExpiresIn(tokens.expiresIn);
        zamestnanec.setRefreshToken(tokens.refreshToken);
        zamestnanec.setScope(tokens.scope);
        ulozZamestnance(zamestnanec);
    }

    /**
     * Vrací AccessTokenResponse pro zadané číslo zaměstnance. Pokud není nalezen
     * je vráceno null.
     *
     * @param zamId zaměstnanecké číslo pro hledaná token
     * @return AccessTokenResponse pro zadané zaměstnanecé číslo
     */
    @Override
    public AccessTokenResponse getToken(Integer zamId) {
        Zamestnanec zamestnanec = getZamestnanec(zamId);
        if (zamestnanec != null) {
            AccessTokenResponse atr = new AccessTokenResponse();
            atr.accessToken = zamestnanec.getAccessToken();
            atr.expiresIn = zamestnanec.getExpiresIn();
            atr.refreshToken = zamestnanec.getRefreshToken();
            atr.scope = zamestnanec.getScope();
            return atr;
        } else {
            return null;
        }
    }
}
